package ar.com.arkios.kfcon4d.util;

import ar.com.arkios.j4d.opConstants;
import ar.com.arkios.j4d.opData;
import ar.com.arkios.j4d.opDataArray;
import ar.com.arkios.j4d.opException;
import ar.com.arkios.j4d.opField;
import ar.com.arkios.j4d.opFieldArray;
import ar.com.arkios.j4d.opProcess;
import ar.com.arkios.j4d.opSearch;
import ar.com.arkios.j4d.opSearchArray;
import ar.com.arkios.j4d.opSelection;
import ar.com.arkios.j4d.opServerProcess;
import ar.com.arkios.j4d.opSet;
import ar.com.arkios.j4d.opTable;
import ar.com.arkios.j4d.opVariable;
import ar.com.arkios.j4d.opVariableArray;
import org.apache.log4j.Logger;

/**
 * Esta clase utilitaria provee métodos para facilitar las operaciones
 * contra 4D.
 */
public class CuatroDUtils {
    
    private static final Logger miLogger = Logger.getLogger(CuatroDUtils.class);
    
    /**
     * Da de alta un varios registros mediante un selecction to array
     * Notas: 
     * 1. no maneja transacciones, si se quiere usarlas, hacerlo en el método que llame a este
     * 2. 
     * 
     * @param elProceso proceso en uso
     * @param losDatos lo que hay que dar de alta
     * @param elRegistro campos del registro a dar de alta, en correspondencia con losDatos
     * @throws ar.com.arkios.j4d.opException
     */
    public static void alta (opProcess elProceso, opDataArray[] losDatos, opFieldArray elRegistro) throws opException {
        short numTabla = elRegistro.mTargetTable;
        reducirAcero(elProceso, numTabla);
        //miLogger.error("Reduccion a cero");
        elProceso.ArrayToSelection(losDatos, elRegistro);
        //miLogger.error("fin transf");
    }
    
    public static void reducirAcero (opProcess elProceso, short elNroTabla) throws opException {
        opSelection seleccion = new opSelection(elNroTabla);
        seleccion.mRecordsInSelection = 0;
        elProceso.ReduceSelection(seleccion);
    }

    /**
     * Busca en modo similar a buscarXlista, pero en una tabla de operativos.
     * Para eso después de la búsqueda hace interseccion con los registros que tengan campo AMano == false
     * 
     * @param elProceso proceso en uso
     * @param losCodigos codigos a buscar
     * @param losCampos opField array para deducir elNroDeTabla y elNroDeCampo
     * @return seleccion que devuelve la búsqueda
     * @throws ar.com.arkios.j4d.opException
     */
    public static opSelection buscarXOperlista (opProcess elProceso, opDataArray losCodigos, opFieldArray losCampos) throws opException {
        opSelection losEncontrados = buscarXlista (elProceso, losCodigos, losCampos); 
        losEncontrados = yNoAMano(elProceso, losCampos.mTargetTable);
        return losEncontrados;
    }
    
    /**
     * Simplemente llama a la otra buscarXOperlista con el primer elemento del opDataArray[]
     * 
     * @param elProceso proceso en uso
     * @param losDatos array de codigos a buscar, del que uso solo su primer dimension
     * @param losCampos opField array para deducir elNroDeTabla y elNroDeCampo
     * @return seleccion que devuelve la búsqueda
     * @throws ar.com.arkios.j4d.opException
     */

    public static opSelection buscarXOperlista (opProcess elProceso, opDataArray[] losDatos, opFieldArray losCampos) throws opException {
        return buscarXOperlista(elProceso, losDatos[0], losCampos);
    }

    /**
     * Busca en modo similar a buscarXlista, pero en una tabla de atributos.
     * Para eso después de la búsqueda hace interseccion con los registros que tengan campo entidad == SAP
     * 
     * @param elProceso proceso en uso
     * @param losCodigos codigos a buscar
     * @param losCampos opField array para deducir elNroDeTabla y elNroDeCampo
     * @return seleccion que devuelve la búsqueda
     * @throws ar.com.arkios.j4d.opException
     */
    public static opSelection buscarXAtributoslista (opProcess elProceso, opDataArray losCodigos, opFieldArray losCampos) throws opException {
        opSelection losEncontrados = buscarXlista (elProceso, losCodigos, losCampos);       
        losEncontrados = ySAP(elProceso, losCampos.mTargetTable);
        return losEncontrados;
    }
    
    /**
     * Simplemente llama a la otra buscarXAtributoslista con el primer elemento del opDataArray[]
     * 
     * @param elProceso proceso en uso
     * @param losDatos array de codigos a buscar, del que uso solo su primer dimension
     * @param losCampos opField array para deducir elNroDeTabla y elNroDeCampo
     * @return seleccion que devuelve la búsqueda
     * @throws ar.com.arkios.j4d.opException
     */

    public static opSelection buscarXAtributoslista (opProcess elProceso, opDataArray[] losDatos, opFieldArray losCampos) throws opException {
        return buscarXAtributoslista(elProceso, losDatos[0], losCampos);
    }
    
    /**
     * Busca los registros correspondientes a los codigos pasados.
     * Es tipo un Query with Array de 4D, es decir busca todos los códigos usando OR
     * 
     * @param elProceso proceso en uso
     * @param losCodigos codigos a buscar
     * @param losCampos opField array para deducir elNroDeTabla y elNroDeCampo
     * @return seleccion que devuelve la búsqueda
     * @throws ar.com.arkios.j4d.opException
     */
    public static opSelection buscarXlista (opProcess elProceso, opDataArray losCodigos, opFieldArray losCampos) throws opException {
        short elNroDeTabla = losCampos.mTargetTable;
        short elNroDeCampo = losCampos.mFieldArray[0].mFieldNumber;
        //miLogger.debug("Buscando --> Tabla: "+elNroDeTabla+" - Campo: "+elNroDeCampo);
        //miLogger.debug("Data: "+losCodigos.mSize+" - Campos: "+losCampos.mSize);
        opSearchArray criterio = new opSearchArray(losCodigos.mSize);
        for (int i = 0; i < criterio.mSize ; i++) {
            criterio.mSearchArray[i] = new opSearch (opConstants.OR, elNroDeTabla, elNroDeCampo, opConstants.EQUAL, losCodigos.mDataArray[i]);
        }
        criterio.mSearchArray[0].mLogicalOperator = opConstants.NONE;
        return elProceso.Search(criterio);
    }
    
    /**
     * Simplemente llama a la otra buscarXlista con el primer elemento del opDataArray[]
     * 
     * @param elProceso proceso en uso
     * @param losDatos array de codigos a buscar, del que uso solo su primer dimension
     * @param losCampos opField array para deducir elNroDeTabla y elNroDeCampo
     * @return seleccion que devuelve la búsqueda
     * @throws ar.com.arkios.j4d.opException
     */
    public static opSelection buscarXlista (opProcess elProceso, opDataArray[] losDatos, opFieldArray losCampos) throws opException {
        return buscarXlista(elProceso, losDatos[0], losCampos);
    }

    /**
     * Ordena por un campo, aquel del que me pasan el nro, en el ordenamiento indicado
     * 
     * @param elProceso proceso en uso
     * @param elNroDeTabla nro de tabla
     * @param elNroDeCampo nro de campo
     * @param odenamiento
     * @throws ar.com.arkios.j4d.opException
     */
    public static void ordenar (opProcess elProceso, short elNroDeTabla, short elNroDeCampo, byte odenamiento) throws opException {
        opFieldArray campoCod = new opFieldArray(1);
        campoCod.mTargetTable = elNroDeTabla;
        campoCod.mFieldArray[0] = new opField(elNroDeTabla, elNroDeCampo);
        campoCod.mFieldArray[0].mOrdering = odenamiento;
        elProceso.OrderBy(campoCod);       
    }
    
    public static void ordenar (opProcess elProceso, opFieldArray elFieldArray, byte odenamiento) throws opException {
        elFieldArray.mFieldArray[0].mOrdering = odenamiento;
        elProceso.OrderBy(elFieldArray);       
    }
    
    /**
     * Arma una seleccion con el complemento de los registros seleccionados
     * @param elProceso proceso en uso
     * @param elNroDeTabla nro de tabla
     * @return cantidad de registros en la seleccion armada
     * @throws ar.com.arkios.j4d.opException
     */
    public static opSelection invertirSeleccion (opProcess elProceso, short elNroDeTabla) throws opException {
        //por algún motivo es fundamental pasar algo >0 como mRecordNumber
        opSet regsAnteriores = new opSet(elNroDeTabla, 1, "Anteriores");
        elProceso.CreateSet(regsAnteriores);
        
        opTable tabla = new opTable(elNroDeTabla);
        elProceso.AllRecords(tabla);
        opSet regsTodos = new opSet(elNroDeTabla, 1, "Todos");
        elProceso.CreateSet(regsTodos);
        
        elProceso.DifferenceSet(regsTodos, regsAnteriores, regsTodos);
        elProceso.ClearSet(regsAnteriores);
        elProceso.UseSet(regsTodos);
        elProceso.ClearSet(regsTodos);
        
        opSelection elComplemento = new opSelection(elNroDeTabla);
        elProceso.RecordsInSelection(elComplemento);
        return elComplemento;
    }

    public static opSelection ySAP(opProcess elProceso, short elNroDeTabla) throws opException {
        opSet regsCods = new opSet(elNroDeTabla, 1, "Codigos");
        elProceso.CreateSet(regsCods);

        opSearchArray criterioSAP = new opSearchArray(1);
        opTable tablaAtributos = new opTable(elNroDeTabla);
        elProceso.GetTableProperties(tablaAtributos);
        short elNroCampoEntidad = EstructuraUtil.getFieldNumber(tablaAtributos, "Ente");
        opData dataSAP = new opData(opConstants.ALPHANUMERIC, EstructuraUtil.SAP);
        criterioSAP.mSearchArray[0] = new opSearch(opConstants.NONE, elNroDeTabla, elNroCampoEntidad, opConstants.EQUAL, dataSAP);

        elProceso.Search(criterioSAP);
        opSet regsSAP = new opSet(elNroDeTabla, 1, "SAP");
        elProceso.CreateSet(regsSAP);

        elProceso.IntersectionSet(regsSAP, regsCods, regsSAP);
        elProceso.ClearSet(regsCods);
        elProceso.UseSet(regsSAP);
        elProceso.ClearSet(regsSAP);

        opSelection losEncontrados = new opSelection(elNroDeTabla);
        elProceso.RecordsInSelection(losEncontrados);
        return losEncontrados;
    }

    public static opSelection yNoAMano(opProcess elProceso, short elNroDeTabla) throws opException {
        opSet regsCods = new opSet(elNroDeTabla, 1, "Codigos");
        elProceso.CreateSet(regsCods);

        opSearchArray criterioSAP = new opSearchArray(1);
        opTable tablaAtributos = new opTable(elNroDeTabla);
        elProceso.GetTableProperties(tablaAtributos);
        short elNroCampoEntidad = EstructuraUtil.getFieldNumber(tablaAtributos, "AMano");
        opData dataSAP = new opData(opConstants.BOOLEAN, false);
        criterioSAP.mSearchArray[0] = new opSearch(opConstants.NONE, elNroDeTabla, elNroCampoEntidad, opConstants.EQUAL, dataSAP);

        elProceso.Search(criterioSAP);
        opSet regsSAP = new opSet(elNroDeTabla, 1, "SAP");
        elProceso.CreateSet(regsSAP);

        elProceso.IntersectionSet(regsSAP, regsCods, regsSAP);
        elProceso.ClearSet(regsCods);
        elProceso.UseSet(regsSAP);
        elProceso.ClearSet(regsSAP);

        opSelection losEncontrados = new opSelection(elNroDeTabla);
        elProceso.RecordsInSelection(losEncontrados);
        return losEncontrados;
    }
    
    public static String GetStringVar (opProcess elProceso, String laVariableNombre, int laVariableTipo, opServerProcess elMetodo4D) throws opException {
        opVariableArray unArrayVar = new opVariableArray(1);
        unArrayVar.mVariableArray[0] = new opVariable(laVariableTipo, laVariableNombre);
        elProceso.GetProcessVariable(elMetodo4D, unArrayVar);
        opData elValorObtenido = unArrayVar.mVariableArray[0].mData;
        return elValorObtenido.mString == null ? "" : elValorObtenido.mString;
    }
    
    public static void SetStringVar (opProcess elProceso, String laVariableNombre, int laVariableTipo, opServerProcess elMetodo4D, String elValorAPoner) throws opException {
        SetHitzaVar(elProceso, laVariableNombre, laVariableTipo, elMetodo4D, elValorAPoner, opConstants.ALPHANUMERIC2);
    }

    // Modificado por Ale 18-05-09. Sincronizo el metodo IT 1239 
    public static synchronized void SetTextVar (opProcess elProceso, String laVariableNombre, int laVariableTipo, opServerProcess elMetodo4D, String elValorAPoner) throws opException {
        SetHitzaVar(elProceso, laVariableNombre, laVariableTipo, elMetodo4D, elValorAPoner, opConstants.TEXT);
    }
    
    private static void SetHitzaVar (opProcess elProceso, String laVariableNombre, int laVariableTipo, opServerProcess elMetodo4D, String elValorAPoner, short laVariableClase) throws opException {
        opVariableArray unArrayVar = new opVariableArray(1);
        unArrayVar.mVariableArray[0] = new opVariable(laVariableTipo, laVariableNombre);
        unArrayVar.mVariableArray[0].mData = new opData(laVariableClase, elValorAPoner);
        elProceso.SetProcessVariable(elMetodo4D, unArrayVar);
    }
    
}